
GLE.DragControls = function (_objects, _camera, _domElement) {

    if (_objects instanceof GLE.Camera) {
        var temp = _objects; _objects = _camera; _camera = temp;

    }

    var _plane = new GLE.Plane();
    var _raycaster = new GLE.Raycaster();

    var _mouse = new GLE.Vector2();
    var _offset = new GLE.Vector3();
    var _intersection = new GLE.Vector3();


    var onDownPosition = new GLE.Vector2();
    var onUpPosition = new GLE.Vector2();

    var _selected = null, _hovered = null;

    var scope = this;
    this.objects = _objects;

    function activate() {
        _domElement.addEventListener('mousedown', onDocumentMouseDown, false);
        _domElement.addEventListener('mouseup', onDocumentMouseCancel, false);
        _domElement.addEventListener('touchstart', onDocumentTouchStart, false);
        _domElement.addEventListener('touchend', onDocumentTouchEnd, false);

    }

    function deactivate() {
        _domElement.removeEventListener('mousedown', onDocumentMouseDown, false);
        _domElement.removeEventListener('mouseup', onDocumentMouseCancel, false);
        _domElement.removeEventListener('touchstart', onDocumentTouchStart, false);
        _domElement.removeEventListener('touchend', onDocumentTouchEnd, false);

    }

    function dispose() {

        deactivate();

    }


    function onDocumentMouseDown(event) {

        event.preventDefault();

        var rect = _domElement.getBoundingClientRect();

        _mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        _mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

        onDownPosition.fromArray([_mouse.x, _mouse.y]);

        _raycaster.setFromCamera(_mouse, _camera);

        if (_selected && scope.enabled) {

            if (_raycaster.ray.intersectPlane(_plane, _intersection)) {

                _selected.position.copy(_intersection.sub(_offset));

            }

            _domElement.style.cursor = 'move';
            scope.dispatchEvent({ type: 'dragstart', object: _selected });

        }

    }


    function handleClick() {
        if (onDownPosition.distanceTo(onUpPosition) === 0) {
            var intersects = _raycaster.intersectObjects(scope.objects, true);

            if (intersects.length > 0) {

                _selected = intersects[0].object;


                var objname = _selected.name;

                if (objname.indexOf("scene") <= -1) {
                    _selected = _selected.parent;
                }
            }
        }
    }

    function onDocumentMouseCancel(event) {

        event.preventDefault();

        if (scope.objects.length == 0) {
            return;
        }
        if (scope.objects[0].parent.name.indexOf("sceneobj")>-1)
        {
            return;
        }

        var rect = _domElement.getBoundingClientRect();

        _mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        _mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

        onUpPosition.fromArray([_mouse.x, _mouse.y]);

        var intersects = _raycaster.intersectObjects(scope.objects,true);
        if (onDownPosition.distanceTo(onUpPosition) === 0) {
            if (intersects.length > 0) {

                var object = intersects[0].object;

                _plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), object.position);

                if (_hovered !== object) {
                    scope.dispatchEvent({ type: 'mouseup', object: object });
                    _hovered = object;

                    _domElement.style.cursor = 'pointer';

                }

            } else {

                if (_hovered !== null) {

                    scope.dispatchEvent({ type: 'mouseleave', object: _hovered });

                    _domElement.style.cursor = 'auto';
                    _hovered = null;

                }

            }
        }

        handleClick();


        if (_selected) {

            scope.dispatchEvent({ type: 'dragend', object: _selected });

            _selected = null;

        }

        _domElement.style.cursor = _hovered ? 'pointer' : 'auto';

    }

    function onDocumentTouchStart(event) {

        event.preventDefault();
        event = event.changedTouches[0];

        var rect = _domElement.getBoundingClientRect();

        _mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        _mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

        _raycaster.setFromCamera(_mouse, _camera);

        onDownPosition.fromArray([_mouse.x, _mouse.y]);

        var intersects = _raycaster.intersectObjects(scope.objects);

        if (intersects.length > 0) {

            _domElement.style.cursor = 'move';

            scope.dispatchEvent({ type: 'dragstart', object: _selected });

        }

    }

    function onDocumentTouchEnd(event) {

        event.preventDefault();

        var rect = _domElement.getBoundingClientRect();

        _mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        _mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

        onUpPosition.fromArray([_mouse.x, _mouse.y]);

        handleClick();

        if (_selected) {

            scope.dispatchEvent({ type: 'dragend', object: _selected });

            _selected = null;

        }

        _domElement.style.cursor = 'auto';

    }

    activate();

    this.enabled = true;

    this.activate = activate;
    this.deactivate = deactivate;
    this.dispose = dispose;

    this.setObjects = function () {

    };

    this.on = function (type, listener) {
        scope.addEventListener(type, listener);

    };

    this.off = function (type, listener) {
        scope.removeEventListener(type, listener);
    };

    this.notify = function (type) {
        scope.dispatchEvent({ type: type });
    };
};

GLE.DragControls.prototype = Object.create(GLE.EventDispatcher.prototype);
GLE.DragControls.prototype.constructor = GLE.DragControls;
